[New Permission 4/5] smartcontract: define topology/resource/index permission flags#3942
Merged
Merged
Conversation
bgm-malbeclabs
approved these changes
Jun 29, 2026
f9a4ff5 to
8e8e6ac
Compare
elitegreg
approved these changes
Jun 29, 2026
- Add execute_authorized_transaction_quiet to DoubleZeroClient trait and DZClient impl, restoring quiet mode for ban and closeaccount commands that was lost when switching to execute_authorized_transaction - Restore onchain allocation support in CreateSubscribeUserCommand SDK command (feature-flag-gated ResourceExtension PDA logic removed in permission enforcement refactor) - Restore atomic path tests and fixture resource extension PDA fields in create_subscribe_user_test.rs
- SDK: route execute_transaction and execute_authorized_transaction through a single execute_transaction_inner, restoring the protocol-max compute-budget / heap-frame requests, skip_preflight, and structured error handling that the build_and_send detour had dropped for the whole SDK (C1/H1). - SDK: append the Permission PDA as the trailing account so it stays after payer+system, matching authorize()'s read order; the quiet authorized variant now shares the same builder (H2/H3/L3). - SDK: memoize the Permission PDA lookup and retry it on transient RPC errors, removing the per-send un-retried get_account (M3). - SDK: add DZClient-level tests asserting compute-budget presence and the trailing Permission account, with and without a permission account (M2). - authorize: drop the retired activator authority from USER_ADMIN/NETWORK_ADMIN/ MULTICAST_ADMIN legacy fallbacks; document the ACCESS_PASS_ADMIN expansion (M1). - authorize: verify program ownership before inspecting account data (L1). - accesspass/set: document the optional-account count invariant (M4). - CHANGELOG: correct the SDK entry to match the unified builder.
…delete/ban DeleteUserCommand and RequestBanUserCommand authorize the final instruction with USER_ADMIN, but first strip the user's multicast roles through UpdateMulticastGroupRoles, whose processor only accepted the access-pass owner or a foundation member. A USER_ADMIN-only payer was therefore blocked on the prerequisite cleanup. Allow the role-update processor to accept USER_ADMIN for the removal-only case (no roles being granted), and route UpdateMulticastGroupRolesCommand through execute_authorized_transaction so the payer's Permission account is appended when present. Adding roles still requires the owner or foundation.
…to-injection The SDK auto-appends the payer's Permission PDA whenever it exists on-chain, so a foundation member whose own Permission account was suspended, under-privileged, or uninitialized was routed through the Some branch of authorize() and denied the PERMISSION_ADMIN instruction needed to repair it — the None-branch lockout fallback never ran. Extract foundation_permission_recovery() and apply it in the Some branch too: when the supplied Permission account does not grant the flag, a foundation member requesting PERMISSION_ADMIN is still allowed. PDA-address and ownership checks remain hard errors; recovery is scoped to PERMISSION_ADMIN only.
20dcbed to
1ccffdb
Compare
…rmission flags Add TOPOLOGY_ADMIN (1<<15), RESOURCE_ADMIN (1<<16), and INDEX_ADMIN (1<<17) to permission_flags, with legacy authorization mapping each to the foundation allowlist in authorize() (plus unit tests). Expose the new names in the serviceability CLI (topology-admin/resource-admin/index-admin) and add the matching constants to the Go, TypeScript, and Python SDKs. Documents the flags in PERMISSION.md and the serviceability README. This defines the permissions; enforcement in the processors lands in 4/4.
696cfc3 to
0c9e787
Compare
juan-malbeclabs
added a commit
that referenced
this pull request
Jun 30, 2026
…ation in existing instructions (#3206) > **Permission rollout — stacked PR series.** Review/merge order: > 1. [#3206 — enforce Permission-based authorization in existing instructions](#3206) > 2. [#3942 — define topology/resource/index permission flags (3/4)](#3942) — stacked on #3206 > 3. [#3943 — enforce topology/resource/index permission flags (4/4)](#3943) — stacked on #3942 > > Retarget each PR's base to `main` as its upstream merges. > **👉 You are here: #3206 (base of the follow-up stack).** ## Summary of Changes - Wire `authorize()` into the privileged instruction processors that gate on it: `accesspass/{close,set}` (`ACCESS_PASS_ADMIN`) and `user/{delete,requestban}` (`USER_ADMIN`). Each appends the caller's Permission PDA as an optional trailing account, read last by `authorize()`. The user owner can still delete their own account without a Permission account. - Add `execute_authorized_transaction` (and its `_quiet` variant) to the Rust SDK. They share the existing `execute_transaction_inner` builder, so compute-budget, preflight, and error-reporting behavior are identical to `execute_transaction`; the only difference is the optional trailing Permission PDA, which is resolved at most once per client (retried on transient RPC errors, then memoized). - Switch the affected SDK commands (`accesspass/{close,set}`, `user/{delete,requestban}`, `tenant/delete`, and the `permission/*` CRUD commands) to `execute_authorized_transaction` so the Permission account is included transparently. - Drop the retired activator authority from the `USER_ADMIN`/`NETWORK_ADMIN`/`MULTICAST_ADMIN` legacy fallbacks. `ACCESS_PASS_ADMIN` legacy authority (foundation + sentinel + feed) is applied uniformly across its instructions and documented in `authorize.rs`. ## Testing Verification - New DZClient-level tests assert the assembled instruction list carries the protocol-max compute-budget/heap-frame requests and that the Permission account is appended after `payer`+`system`, with and without an on-chain permission account. - `authorize` unit tests cover the legacy fallbacks (including the activator now being denied for the admin roles) and the Permission-account path (PDA, ownership, discriminator, status, and flag checks). - `cargo test -p doublezero_sdk` and `cargo test -p doublezero-serviceability` pass. Related RFC/series: the Permission account and `authorize()` mechanism land in the earlier PRs of this series; this PR enforces them in existing instructions.
juan-malbeclabs
added a commit
that referenced
this pull request
Jun 30, 2026
…ermission flags (#3943) > **Permission rollout — stacked PR series.** Review/merge order: > 1. [#3206 — enforce Permission-based authorization in existing instructions](#3206) > 2. [#3942 — define topology/resource/index permission flags (3/4)](#3942) — stacked on #3206 > 3. [#3943 — enforce topology/resource/index permission flags (4/4)](#3943) — stacked on #3942 > > Retarget each PR's base to `main` as its upstream merges. > **👉 You are here: #3943 (PR 4/4).** ## Summary - Replaces the direct `foundation_allowlist` checks with `authorize()` in topology (`create` / `delete` / `clear` / `assign-node-segments`) → `TOPOLOGY_ADMIN`, resource (`create` / `allocate` / `deallocate` / `close`) → `RESOURCE_ADMIN`, and index (`create` / `delete`) → `INDEX_ADMIN`. - The `Permission` account is read as the optional trailing account; the variable-length `clear` and `assign-node-segments` layouts detect it by PDA match before consuming their link/device lists. - Backward compatible: with no `Permission` account the legacy foundation path still applies, so existing callers (controlplane, current SDK) keep working. - Switches the corresponding SDK commands to `execute_authorized_transaction` so the payer's `Permission` PDA is appended when it exists onchain. **Behavior change:** the topology instructions now reject unauthorized callers with `NotAllowed` (`Custom(8)`) instead of `Unauthorized` (`Custom(22)`), since `authorize()` is the single rejection path; affected tests updated. Depends on the 3/4 PR (stacked). ## Testing Verification - New end-to-end test `test_topology_create_with_permission_account_allowed`: a non-foundation key holding `TOPOLOGY_ADMIN` creates a topology via its `Permission` account — exercises the new authorization path through a real processor. - topology / index / resource / permission integration suites pass; topology error-code assertions updated `Unauthorized` → `NotAllowed`. Reference: `smartcontract/programs/doublezero-serviceability/PERMISSION.md`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TOPOLOGY_ADMIN(1<<15),RESOURCE_ADMIN(1<<16),INDEX_ADMIN(1<<17) — so segment-routing topologies,ResourceExtensionaccounts, and internalIndexaccounts can be delegated without granting the broadFOUNDATIONflag (today they are foundation-only).foundation_allowlistinauthorize()'s legacy path, so authorization behavior is unchanged until aPermissionaccount is supplied.topology-admin/resource-admin/index-admin) in the serviceability CLI forpermission set --add/--remove, and adds matching constants to the Go, TypeScript, and Python SDKs.PERMISSION.mdand the serviceabilityREADME.md.This PR is definition-only; processor enforcement lands in the follow-up 4/4. Stacked on #3206.
Testing Verification
authorize()legacy-mapping unit tests for each new flag (allowed via a foundation member, denied for others).Reference:
smartcontract/programs/doublezero-serviceability/PERMISSION.md